//-----------------------------------------------------------------------
// <copyright file="MockeryAcceptanceTest.cs" company="NMock2">
//
//   http://www.sourceforge.net/projects/NMock2
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
// </copyright>
// This is the easiest way to ignore StyleCop rules on this file, even if we shouldn't use this tag:
// <auto-generated />
//-----------------------------------------------------------------------
namespace NMock2.AcceptanceTests
{
    using System.Collections;
    using System.ComponentModel.Design;
    using NMock2.Internal;
    using NMock2.Monitoring;
    using NUnit.Framework;
    using System;

    [TestFixture]
    public class MockeryAcceptanceTest : AcceptanceTestBase
    {
        [TestFixtureSetUp]
        public void TestFixtureSetUp()
        {
            SkipVerificationForThisFixture();
        }

        [TearDown]
		public void TearDown()
		{
			// We're mucking around with changing the default IMockObjectFactory in some tests
			// in this fixture. Here we restore things back to normal after each test.
            SetupFixture.SetMockObjectFactoryToDefault();
		}

        [Test]
        public void CallingVerifyOnMockeryShouldEnableMockeryToBeUsedSuccessfullyForOtherTests()
        {
            IMockedType mockWithUninvokedExpectations = (IMockedType)Mocks.NewMock(typeof(IMockedType));
            Expect.Once.On(mockWithUninvokedExpectations).Method("Method").WithNoArguments();
            try
            {
                Mocks.VerifyAllExpectationsHaveBeenMet();
                Assert.Fail("Expected ExpectationException to be thrown");
            }
            catch (ExpectationException expected)
            {
                Assert.IsTrue(expected.Message.IndexOf("Not all expected invocations were performed.") != -1);
            }

            IMockedType mockWithInvokedExpectations = (IMockedType)Mocks.NewMock(typeof(IMockedType));
            Expect.Once.On(mockWithInvokedExpectations).Method("Method").WithNoArguments();
            mockWithInvokedExpectations.Method();
            Mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void MockObjectsMayBePlacedIntoServiceContainers()
        {
            ServiceContainer container = new ServiceContainer();
            IMockedType mockedType = Mocks.NewMock(typeof(IMockedType)) as IMockedType;

            container.AddService(typeof(IMockedType), mockedType);

            Assert.AreSame(mockedType, container.GetService(typeof(IMockedType)));
        }

		[Test]
		public void ChangingDefaultMockObjectFactoryChangesBehaviourOfNewMockeryInstances()
		{
			Mockery.ChangeDefaultMockObjectFactory(typeof(TestingMockObjectFactoryA));
			Mockery mocksA = new Mockery();
			Assert.AreEqual("TestingMockObjectFactoryA", mocksA.NewMock<INamed>().GetName());

			Mockery.ChangeDefaultMockObjectFactory(typeof(TestingMockObjectFactoryB));
			Mockery mocksB = new Mockery();
			Assert.AreEqual("TestingMockObjectFactoryB", mocksB.NewMock<INamed>().GetName());
		}

		[Test]
		public void ChangingDefaultMockObjectFactoryDoesNotAffectExistingMockeryInstances()
		{
			Mockery.ChangeDefaultMockObjectFactory(typeof(TestingMockObjectFactoryA));
			Mockery mocks = new Mockery();
			Mockery.ChangeDefaultMockObjectFactory(typeof(TestingMockObjectFactoryB));

			Assert.AreEqual("TestingMockObjectFactoryA", mocks.NewMock<INamed>().GetName());
		}

        [Test, ExpectedException(typeof(InvalidOperationException))]
        public void SpecifyingConstructorArgsTwiceWhenCreatingMockThrowsInvalidOperationException()
        {
            Mocks.NewMock<SomeBaseClass>(DefinedAs.WithArgs("ABC").WithArgs("DEF"));
        }

        [Test, ExpectedException(typeof(InvalidOperationException))]
        public void SpecifyingMockStyleTwiceWhenCreatingMockThrowsInvalidOperationException()
        {
            Mocks.NewMock<IMockedType>(DefinedAs.OfStyle(MockStyle.Stub).OfStyle(MockStyle.Transparent));
        }

        [Test, ExpectedException(typeof(InvalidOperationException))]
        public void SpecifyingNameTwiceWhenCreatingMockThrowsInvalidOperationException()
        {
            Mocks.NewMock<IMockedType>(DefinedAs.Named("A").Named("B"));
        }

        [Test, Class]
        public void CanMakeMultipleCallsToImplementingWhenCreatingMock()
        {
            var mock = Mocks.NewMock<IMockedType>(DefinedAs.Implementing<IEnumerable>().Implementing<IDisposable>());

            Assert.IsInstanceOfType(typeof(IMockedType), mock);
            Assert.IsInstanceOfType(typeof(IEnumerable), mock);
            Assert.IsInstanceOfType(typeof(IDisposable), mock);
        }
    }

    public interface IMockedType
    {
        void Method();
    }

	public interface INamed
	{
		string GetName();
	}

	public class Named : INamed
	{
		private string name;

		public Named(string name)
		{
			this.name = name;
		}

		public string GetName()
		{
			return name;
		}
	}

    public class SomeBaseClass
    {
        public SomeBaseClass(string input)
        {
                
        }
    }

	public class TestingMockObjectFactoryA : IMockObjectFactory
	{
        public object CreateMock(Mockery mockery, CompositeType mockedTypes, string name, MockStyle mockStyle, object[] constructorArgs)
		{
			return new Named(this.GetType().Name);
		}
	}

	public class TestingMockObjectFactoryB : TestingMockObjectFactoryA
	{
		
	}
}